package org.softmed.reflection.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MapperManager {

	Map<Class, MapperConfig> map = new HashMap<Class, MapperConfig>();



	public MapperConfig check(Class type) {
		MapperConfig mc = map.get(type);
		if (mc != null)
			return mc;

		return buildConfig(type);

	}

	protected MapperConfig buildConfig(Class type) {

		MapperConfig mconfig = new MapperConfig(type);
		Method[] methods = type.getMethods();

		List<Method> candidateSetters = new ArrayList<Method>();
		List<Method> candidateGetters = new ArrayList<Method>();

		Method m = null;
		for (int i = 0; i < methods.length; i++) {
			m = methods[i];
			if (m.getName().startsWith("set"))
				candidateSetters.add(m);
			else if (m.getName().startsWith("get")
					|| m.getName().startsWith("is"))
				candidateGetters.add(m);
		}

		return buildCompatibleConfig(type, mconfig, candidateSetters,
				candidateGetters);

	}

	protected MapperConfig buildCompatibleConfig(Class type,
			MapperConfig mconfig, List<Method> candidateSetters,
			List<Method> candidateGetters) {
		String field = null;
		for (Method method : candidateSetters) {
			if (isValid(method)) {
				field = method.getName().substring(3);
				String getterName = "get" + field;
				String isName = "is" + field;
				for (Method possibleGetter : candidateGetters) {
					if (possibleGetter.getName().equals(getterName)
							|| possibleGetter.getName().equals(isName)) {
						// compare types
						Class[] ptypes = method.getParameterTypes();
						if (possibleGetter.getReturnType() == ptypes[0]) {
							mconfig.addPair(field, possibleGetter
									.getReturnType(), possibleGetter, method);
							break;
						}

					}
				}

			}

		}

		map.put(type, mconfig);

		return mconfig;
	}

	protected boolean isValid(Method method) {
		if (method.getName().startsWith("set")
				&& method.getReturnType() == void.class) {

			Class[] ptypes = method.getParameterTypes();
			if (ptypes.length == 1)
				return true;
		}
		return false;

	}

}
